package com.example.springboot.controller.参数解析;

import com.example.springboot.bean.Pet;
import com.example.springboot.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class 返回值处理 {

    /**
     * 3.参数返回处理 执行目标方法后执行
     *    对加了@ResponseBody 的方法的返回值进行处理
     *   返回值处理器  15种 XxxMethodReturnValueHandler .
     *   支持哪几种返回值(如 map，Model,ModelAndView，ModelMap等)
     *   //可以自定义
     *   先遍历 查看是否是异步的  再交给返回值处理器(默认15种)
     *   0 = {ModelAndViewMethodRetumValueHandler@5835} // @5835 会随时变
     *   1 = {ModelMethodProcessor@5836}
     *   2 = {ViewMethodReturnValueHandler@5837}
     *   3 = {ResponseBodyEmitterReturmValueHandler@5838}
     *   4 = {StreamingResponseBodyReturnValueHandler@5839}
     *   5 = {HttpEntityMethodProcessor@5840}
     *   6 = {HttpHeadersReturValueHandler@5841}
     *   7 = {CallableMethodRetumValueHandler@5842}
     *   8 = {DeferredResultMethodRetumValueHandler@5843}
     *   9 = {AsyncTaskMethodReturnValueHandler@5844}
     *   10 = {ModelAttributeMethodProcessor@5845}
     *         @ModelAttribute 注解(类似于) @RequestMapping
     *         不过返回值会保存在隐含的Model里 不进行页面跳转
     *   11 = {RequestResponseBodyMethodProcessor@5846}
     *          有 @ResponseBody 注解的，用这个处理器
     *   12 = {ViewNameMethodReturnValueHandler@5847}
     *   13 = {MapMethodProcessor@5848}
     *   14 = {ModelAttributeMethodProcessor@5849}
     * ● 1、返回值处理器判断是否支持这种类型返回值 supportsReturnType
     * ● 2、支持了返回值处理器调用 handleReturnValue 进行处理
     * ● 3、RequestResponseBodyMethodProcessor 可以处理返回值标了 @ResponseBody 注解的。
     *   ○ 1.  利用 MessageConverters(消息转换器) 进行处理 将数据写为json
     *     ■ 1、内容协商（浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型）
     *          请求头中Accept字段。Http协议中规定的，告诉服务器本客户端可以接收的数据类型。
     *          ● 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化。(请求头 告诉了)
     *     ■ 2、服务器最终根据自己自身的能力，决定服务器能生产出什么样内容类型的数据，
     *          (请求头 告诉了的类型，和服务器能生产的类型，进行匹配 复杂度N*N)
     *     ■ 3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ，看谁能处理？
     *                XxxMessageConverter 接口有5个方法
     *                canRead 是否能读      canWrite 是否能写
     *                getSupportedMediaTypes 获取支持的媒体类型
     *                read  (能读了)读      write(能写了)写
     *           0 = {ByteArrayHttpMessageConverter@6214}           支持Byte类型的
     *           1 = {StringHttpMessageConverter@6221}              支持String
     *           2 = {StringHttpMessageConverter@6222}              支持String
     *           3 = {ResourceHttpMessageConverter@6223}            支持Resource
     *           4 = {ResourceRegionHttpMessageConverter@6224}      支持ResourceRegion
     *           5 = {SourceHttpMessageConverter@6225}
     *              支持DOMSource.class\SAXSource.class\StAXSource.class\StreamSource.class\Source.class
     *           6 = {AllEncompassingFormHttpMessageConverter@6226}   支持MultiValueMap
     *           7 = {MappingJackson2HttpMessageConverter@6227}       支持true
     *           8 = {MappingJackson2HttpMessageConverter@6228}       支持true
     *       当导入xml包的时候 就没了 //9 = {Jaxb2RootElementHttpMessageConverter@6229}      支持支持注解方式xml处理的。
     *           9 = {MappingJackson2XmlHttpMessageConverter@6178}
     *           10 = {MappingJackson2XmlHttpMessageConverter@6179}
     *             当导入了 xml的包的时候  内部写死了 直接加载 9 10
     *       ● 1、得到MappingJackson2HttpMessageConverter可以将对象写为json
     *       ● 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
     *     根据客户端接收能力不同，返回不同媒体类型的数据。
     *
     *      会先判断有没有拦截器给他指定类型 之后
     *       它会根据  浏览器的请求头    获取能接受的数据类型
     *            contentNegotiationManager 内容协商管理器 默认使用基于请求头的策略
     *        再获取能产出的数据类型    进行匹配 复杂度N*N
     *           HeaderContentNegotiationStrategy  确定客户端可以接收的内容类型
     *      把能匹配的  添加在一个数组里   找到最佳匹配 （有转换权重   权重大的优先）经行封装 返回
     *
     *
     *    可以开启基于参数的内容协商
     *       如果浏览器  想要自定义 想要什么  就要什么  可以开启基于参数的内容协商 （在配置文件中）
     *       spring:
     *         mvc:
     *           contentnegotiation:
     *             favor-parameter:true  #true  开启 默认false
     *          开启后 他会再得到请求头的内容协商 前     (优先级最高)
     *          获取一个基于参数的内容协商 而且参数是 format  但是只支持 json 和 xml
     *       在网址中加 http://localhost:8080/test/user?format=json
     *       表示返回json数据  优先级最高
     *      在maven里添加一个xml  依赖   如果浏览器的请求头xml优先级高   就会优先转换成xml
     *
     *
     */

    /**
     * 自定义Message Converter
     *  自定义后，能产出的类型会添加进去
     * 可以自己配置  详见 com.example.springboot.config.LongMessageConverters
     *
     * 也可以将自定义类型  添加在基于参数的内容协商
     *  详见 com.example.springboot.config.MyWebMvcConfigurer.configureContentNegotiation()
     *    这个是重写 所以会覆盖  原来的 xml 和 json  所以要再写一遍
     * 浏览器发请求直接返回xml              【application/xml】
     * 如果是ajax请求返回json              【application/json】
     * 如果自定义app发请求，返回自定义协议数据   【application/x-long】
     *
     */
    @ResponseBody //会给前端自动返回JSON数据!利用返回值处理器里面的消息转换器进行处理
    @GetMapping("/users")
    public User getUser(){
        User user = new User();
        user.setAge(23);
        user.setName("周杰伦");
        user.setPet(new Pet("宠物",60.5));
        return user;
    }
}
